#include "Operacion.h"
#include "HidratadorMetadataClase.h"

using namespace Comun;

namespace CapaIndices
{

	Operacion::Operacion (MetadataClase* MC): _MetadataClase(MC)
	{
		this->Resultado = new list<Registro>();
		_CantRegistrosAfectados=0;
	};

	Operacion::Operacion()
	{
		this->Resultado = new list<Registro>();
		_CantRegistrosAfectados=0;
	};

	Operacion::~Operacion()
	{
	};

	list<Registro>* Operacion::getResultado()
	{
		return Resultado;
	};

	bool Operacion::esSeleccion()
	{
		return false;
	};

	bool Operacion::esDeMetadata()
	{
		return false;
	};

	bool Operacion::esInsercion()
	{
		return false;
	};

	bool Operacion::esAltaClase()
	{
		return false;
	};

	int Operacion::getCantRegAfectados()
	{
		return _CantRegistrosAfectados;
	};

	MetadataClase& Operacion::getMetadataClase()
	{
		return *_MetadataClase;
	};

	void Operacion::InsertarAtributos(MetadatosIndice& MI,InfoIndice* IIndex)
	{
		MI.NombreArchivo=getNombreArch(IIndex);
		MI.NombreClase=getMetadataClase().getClase();
		ClaveValor cv;
		switch (IIndex->getTipoImplementacion()){
				case iHash:
					cv.Clave="tamanoBucket";
					cv.Valor=UIntToString(IIndex->getTamanioBucket());
					MI.Atributos.push_back(cv);
					cv.Clave="organizacionRegistros";
					cv.Valor=(getMetadataClase().getOrganizacionReg()==iRF)?"RF":"RVF";
					MI.Atributos.push_back(cv);
					break;
				case iArbolBPlus:
					cv.Clave="TamanioBloque";
					cv.Valor=IntToString(IIndex->getTamanioNodo());
					MI.Atributos.push_back(cv);
					break;
		}

	};

	string Operacion::IntToString(int i)
	{
		string s;
		stringstream ss;
		ss << i;
		ss >> s;
		return s;
	};

	string Operacion::UIntToString(unsigned int i)
	{
		string s;
		stringstream ss;
		ss << i;
		ss >> s;
		return s;
	};

	/// Devuelve la implemetacion por defecto del Indice.
	/// @param InfoIndex Informacion necesaria para generar el indice.
	/// @return El IIndice con la implementacion por defecto.
	IIndice* Operacion::getIndicePorDefecto()
	{
		MetadatosIndice* metadatosIndices = new MetadatosIndice();

		if (getMetadataClase().getOrganizacionReg() == iRF)
		{
			metadatosIndices->TipoDato = Monovalente;
		}
		else if (getMetadataClase().getOrganizacionReg() == iRVB)
		{
			metadatosIndices->TipoDato = Polivalente;
		}
		else
		{
			cerr << "CapaIndices->Operacion.cpp->Operacion::getIndicePorDefecto()" << endl << "No se reconoce el la organizacion de registros de la clase." << endl;
			throw exception();
		}

		metadatosIndices->NombreClase = getMetadataClase().getClase();

		return new Secuencial(metadatosIndices);
	};

	IIndice* Operacion::getIndice(InfoIndice* InfoIndex)
	{

		MetadatosIndice* MetadIndex=new MetadatosIndice();
		list<AtributoClase> ss = getMetadataClase().getAtributos();

		for (list<AtributoClase>::iterator it = ss.begin(); it != ss.end(); it++)
		{
			MetadatosAtributo mat(it->getNombre(),it->getTipo());
			MetadIndex->CamposRegsitro.push_back(mat);
		}

		if (InfoIndex->esPrimario())
		{
			agregarClavePrimaria(&(MetadIndex->Claves));
			MetadIndex->Tipo = Griego;
		}
		else
		{				
			agregarClavePrimaria(&(MetadIndex->ClavePrimaria));
			agregarClaveSecundariaActual(&(MetadIndex->Claves),InfoIndex);

			MetadIndex->Tipo = Romano;
		}

		if (getMetadataClase().getOrganizacionReg() == iRF)
			MetadIndex->TipoDato=Monovalente;
		else
			MetadIndex->TipoDato=Polivalente;

		InsertarAtributos(*MetadIndex,InfoIndex);

		IIndice* Indice;

		switch (InfoIndex->getTipoImplementacion()){
				case iArbolBPlus:
					Indice=new ArbolBMas(MetadIndex);
					break;
				case iHash:
					Indice=new HashExtensible(MetadIndex);
					break;
		}

		return Indice;
	};

	bool Operacion::TengoInfoIndicePrimario(IIndice* primario,CondicionCompuesta* _CondicionCompuesta)
	{
		bool Result=true;
		for (list<MetadatosAtributo>::iterator it=primario->Metadata->Claves.begin(); ((it!=primario->Metadata->Claves.end()) && (Result));++it){
			Result=false;

			for (list<Condicion*>::iterator itC=_CondicionCompuesta->Subcondiciones.begin();itC!=_CondicionCompuesta->Subcondiciones.end();++itC){
				if ((*itC)->ValorCondicion.Nombre==(*it).Nombre){
					Result=true;
				}
			}
		}
		return Result;			
	};

	list<IIndice*>* Operacion::getIndices()
	{
		list<IIndice*>* ListaIndices=new list<IIndice*>;
		ListaIndices->push_back(getIndice(getMetadataClase().getIndicePrimario()));
		for (list<InfoIndice*>::iterator it=getMetadataClase().getIndicesSecundarios().begin();
			it!=getMetadataClase().getIndicesSecundarios().end();
			++it){
				ListaIndices->push_back(getIndice(*it));
		}
		return ListaIndices;
	};

	void Operacion::agregarClavePrimaria(list<MetadatosAtributo>* Claves)
	{
		MetadatosAtributo MA(" ",Entero);
		for(list<string>::iterator it=getMetadataClase().getIndicePrimario()->getCampos().begin();
			it!=getMetadataClase().getIndicePrimario()->getCampos().end();
			++it){
				MA.Nombre=(*it);
				MA.Tipo=getMetadataClase().getTipoAtributo(*it);
				Claves->push_back(MA);
		}

	};

	void Operacion::agregarClaveSecundariaActual(list<MetadatosAtributo>* Claves,InfoIndice* InfIndex)
	{
		MetadatosAtributo MA(" ",Entero);
		for(list<string>::iterator it=InfIndex->getCampos().begin();
			it!=InfIndex->getCampos().end();
			++it){
				MA.Nombre=(*it);
				MA.Tipo=getMetadataClase().getTipoAtributo(*it);
				Claves->push_back(MA);
		}
	};

	string Operacion::getNombreArch(InfoIndice* InfoIndex)
	{
		return getMetadataClase().getClase() + ".Index" + getStrIndexs(InfoIndex);
	};

	string Operacion::getStrIndexs(InfoIndice* InfoIndex)
	{
		string val="";
		list<string>::iterator it=InfoIndex->getCampos().begin();
		val+=(*it++);
		while (it!=InfoIndex->getCampos().end()){
			val+="-"+(*it);
			++it;
		}
		return val;
	};

	list<string>* Operacion::obtenerCamposIgual(CondicionCompuesta* CC)
	{
		list<string>* lista=new list<string>;
		for (list<Condicion*>::iterator it=CC->Subcondiciones.begin();
			it!=CC->Subcondiciones.end();++it){
				if ((*it)->Simbolo==Igual){
					lista->push_back((*it)->ValorCondicion.Nombre);
				}
		}
		return lista;
	};

	list<string>* Operacion::obtenerCampos(CondicionCompuesta* CC)
	{
		list<string>* lista=new list<string>;
		for (list<Condicion*>::iterator it=CC->Subcondiciones.begin();
			it!=CC->Subcondiciones.end();++it){
				lista->push_back((*it)->ValorCondicion.Nombre);
		}
		return lista;
	};

	bool Operacion::hayIndiceExclusivoPorCampo(string str)
	{
		bool Encontrado=false;
		if (esClaveUnica(str,getMetadataClase().getIndicePrimario()->getCampos()))
			return true;
		for (list<InfoIndice*>::iterator it=getMetadataClase().getIndicesSecundarios().begin();
			((it!=getMetadataClase().getIndicesSecundarios().end()) && (!Encontrado));
			++it){
				if (esClaveUnica(str,(*it)->getCampos()))
					return true;
		}
		return false;
	};

	bool Operacion::hayIndiceCompuestoPorCampo(string str,CondicionCompuesta* CC)
	{
		bool Encontrado=false;
		if (esPrimerClaveDe(str,getMetadataClase().getIndicePrimario()->getCampos(),CC->Subcondiciones))
			return true;
		for (list<InfoIndice*>::iterator it=getMetadataClase().getIndicesSecundarios().begin();
			((it!=getMetadataClase().getIndicesSecundarios().end()) && (!Encontrado));
			++it){
				if (esPrimerClaveDe(str,(*it)->getCampos(),CC->Subcondiciones))
					return true;
		}
		return false;
	};

	bool Operacion::esClaveUnica(string clave,list<string>& Campos)
	{
		return (((*(Campos.begin()))==clave) && (Campos.size()==1));
	};

	bool Operacion::esPrimerClaveDe(string clave,list<string>& Campos,list<Condicion*> Condiciones)
	{
		list<string>::iterator it=Campos.begin();
		bool encontrado=true;
		if (((*it)==clave) && (Campos.size()>1)){
			++it;
			while ((it!=Campos.end()) && (encontrado)){
				encontrado=false;
				for(list<Condicion*>::iterator it2=Condiciones.begin();
					((it2!=Condiciones.end()) && (!encontrado));++it2){
						if ((*it)==((*it2)->ValorCondicion.Nombre)){
							encontrado =true;
						}
				}
				++it;
			}
			return encontrado;
		}
		return false;
	};

	InfoIndice* Operacion::getInfoIndiceDesdeNombre(string str)
	{
		if (esClaveUnica(str,getMetadataClase().getIndicePrimario()->getCampos()))
			return getMetadataClase().getIndicePrimario();

		for (list<InfoIndice*>::iterator it=getMetadataClase().getIndicesSecundarios().begin();
			it!=getMetadataClase().getIndicesSecundarios().end();
			++it){
				if (esClaveUnica(str,(*it)->getCampos()))
					return (*it);

		}
		cerr << "CapaIndices->Operacion.cpp->Operacion::getInfoIndiceDesdeNombre(string str)" << endl << "No existe un indice por ese campo." << endl;
		throw new exception();
	};

	InfoIndice* Operacion::getInfoIndicePrimerNombreClave(string str,CondicionCompuesta* CC)
	{
		if (esPrimerClaveDe(str,getMetadataClase().getIndicePrimario()->getCampos(),CC->Subcondiciones))
			return getMetadataClase().getIndicePrimario();

		for (list<InfoIndice*>::iterator it=getMetadataClase().getIndicesSecundarios().begin();
			it!=getMetadataClase().getIndicesSecundarios().end();
			++it){
				if (esPrimerClaveDe(str,(*it)->getCampos(),CC->Subcondiciones))
					return (*it);

		}
		cerr << "CapaIndices->Operacion.cpp->Operacion::getInfoIndicePrimerNombreClave(string str,CondicionCompuesta* CC)" << endl << "No existe un indice compuesto por ese campo." << endl;
		throw new exception();
	};

	bool Operacion::CondCompEsAND(CondicionCompuesta* CC)
	{
		return CC->EsAnd();
	};

	OperacionSeleccion::OperacionSeleccion(MetadataClase* MC,CondicionCompuesta* CC,list<string>* ColSel): Operacion(MC), _CondicionCompuesta(CC), _ColSeleccion(ColSel)
	{
	};

	bool OperacionSeleccion::esSeleccion()
	{
		return true;
	};

	void OperacionSeleccion::Ejecutar()
	{
		list<Registro>* Tabla=NULL;
		if (CondCompEsAND(_CondicionCompuesta)){
			Tabla=ProcesarAND();
		}else{
			Tabla=ProcesarOR();
		}
		Resultado=SeleccionarColumnas(Tabla);
	};

	list<Registro>* OperacionSeleccion::SeleccionarColumnas(list<Registro>* Tabla){
		list<Registro>* Salida=new list<Registro>;
		for(list<Registro>::iterator it=Tabla->begin();it!=Tabla->end();++it){
			Salida->push_back(FiltrarColumnas(*it));
		}
		return Salida;
	};

	Registro OperacionSeleccion::FiltrarColumnas(Registro& RegIn){
		Registro* RegOut = new Registro();
		for(list<string>::iterator it=_ColSeleccion->begin();it!=_ColSeleccion->end();++it)
		{
			for(list<Atributo>::iterator it2=RegIn.Atributos.begin();it2!=RegIn.Atributos.end();++it2)
			{
				if ((*it)==(*it2).Nombre)
					RegOut->Atributos.push_back(*it2);
			}
		}

		return *RegOut;		
	};

	bool OperacionSeleccion::mostrarColumna(string NombreCol){
		for(list<string>::iterator it=_ColSeleccion->begin();it!=_ColSeleccion->end();++it){
			if ((*it)==NombreCol)
				return true;
		}
		return false;
	};

	bool OperacionSeleccion::tieneCondFuerteConIndice(CondicionCompuesta* CC){
		for (list<Condicion*>::iterator it=CC->Subcondiciones.begin();
			it!=CC->Subcondiciones.end(); ++it){
				if (((*it)->Simbolo==Igual) &&
					((hayIndiceExclusivoPorCampo((*it)->ValorCondicion.Nombre)) || (hayIndiceCompuestoPorCampo((*it)->ValorCondicion.Nombre,CC)))){
						return true;
				}
		}
		return false;
	};

	list<Registro>* OperacionSeleccion::ProcesarAND(){
		if (tieneCondFuerteConIndice(_CondicionCompuesta)){
			return ProcesarANDCampos(obtenerCamposIgual(_CondicionCompuesta));
		}else{
			return ProcesarANDCampos(obtenerCampos(_CondicionCompuesta));
		}
	};

	list<Registro>* OperacionSeleccion::ProcesarANDCampos(list<string>* Campos){
		IIndice* Indice=NULL;
		bool HayIndices=false;
		for (list<string>::iterator it=Campos->begin();	((it!=Campos->end()) && (!HayIndices)); ++it)
		{
			if (hayIndiceExclusivoPorCampo(*it))
			{
				HayIndices=true;
				Indice=getIndice(getInfoIndiceDesdeNombre(*it));
			}
			else
			{
				if (hayIndiceCompuestoPorCampo(*it,_CondicionCompuesta))
				{
					HayIndices=true;
					Indice=getIndice(getInfoIndicePrimerNombreClave(*it,_CondicionCompuesta));
				}
			}
		}

		Clave* cv=new Clave();
		stringstream* ss = new stringstream();
		*ss <<  "Transacciones/CapaIndices/Resultados/" <<this->numero << ".csv";
		cv->NombreArchivo = ss->str();
		cv->AtributosASeleccionar = _ColSeleccion;
		cv->OtrasCondiciones=_CondicionCompuesta;
		cv->EjecucionMultiple=true;
		if (!HayIndices)
		{
			// Si no encontro un indice uso el por defecto.
			Indice = getIndicePorDefecto();

		}
		else
		{
			for (list<Condicion*>::iterator itDatos=_CondicionCompuesta->Subcondiciones.begin(); itDatos!=_CondicionCompuesta->Subcondiciones.end(); ++itDatos)
			{
				for (list<MetadatosAtributo>::iterator itMetAtrib=Indice->Metadata->Claves.begin();
					itMetAtrib!=Indice->Metadata->Claves.end(); ++itMetAtrib)
				{
					if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
					{
						cv->ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
					}
				}
			}
		}

		cv->IndicePrimario = getIndice(getMetadataClase().getIndicePrimario());

		Indice->BuscarClave(cv);
		_CantRegistrosAfectados=cv->RegistrosAfectados;

		delete Indice;
		Campos->clear();
		cv->FlushResultados(true);
		return cv->Resultado;
	};

	list<Registro>* OperacionSeleccion::ProcesarOR(){
		list<Registro>* Resultados=new list<Registro>;
		list<Condicion*> CondSinIndex;
		IIndice* Indice;

		int nroOr = 0;

		for (list<Condicion*>::iterator it=_CondicionCompuesta->Subcondiciones.begin();
			it!=_CondicionCompuesta->Subcondiciones.end(); ++it){

				if (hayIndiceExclusivoPorCampo((*it)->ValorCondicion.Nombre)){
					Indice=getIndice(getInfoIndiceDesdeNombre((*it)->ValorCondicion.Nombre));
					ProcesarCondicionIndice(Indice,(*it),Resultados,nroOr);
					delete Indice;
				}else{
					//utilizo el indice por defecto
					Indice=getIndicePorDefecto();
					ProcesarCondicionIndice(Indice,(*it),Resultados,nroOr);
				}

				nroOr++;
		}

		Atributo a = (* _CondicionCompuesta->Subcondiciones.begin())->ValorCondicion;
		stringstream* ss = new stringstream();
		*ss <<  "Transacciones/CapaIndices/Resultados/" <<this->numero << ".csv";
		EliminarRegistrosRepetidos(Resultados,nroOr,a,ss->str().c_str());

		return Resultados;
	};

	void OperacionSeleccion::EliminarRegistrosRepetidos(list<Registro>* Result, int nroOr, Atributo orden, string nombreArchivo){
		/*for (list<Registro>::iterator Pivot=Result->begin();Pivot!=Result->end();++Pivot)
		for (list<Registro>::iterator it=Result->begin();it!=Result->end();++it)
		if (Pivot!=it) // no estoy apuntando al mismo elemento de la lista
		if ((*Pivot)==(*it)) //son el mismo registro.. (el op == esta sobregargado)
		it = Result->erase(it); //elimino el elemento repetido de la lista*/

		ofstream* archivo = new ofstream("Or0.tmp",ios::out | ios::app);// ios::in | ios::app);

		for (int i=1; i< nroOr; i++)
		{
			stringstream ss;
			ss << "Or" << i << ".tmp";
			ifstream* archivo2 = new ifstream(ss.str().c_str(),ios::in);		

			string line;
			if (getline(*archivo2,line))
				while (getline(*archivo2,line))
					*archivo << line << endl;

			archivo2->close();
			delete archivo2;
		}

		archivo->close();

		delete archivo;

		Sort* ordenar = new Sort("Or0.tmp",orden,true,true);
		ordenar->SortExterno(nombreArchivo);
		//esta mal.. deberia determinarlo el sort
		_CantRegistrosAfectados=-1;
	};

	void OperacionSeleccion::ProcesarCondicionIndice(IIndice* Index,Condicion* Cnd,list<Registro>* Result, int nro){
		CondicionCompuestaAND CC;
		CC.Subcondiciones.push_back(Cnd);
		Clave* cv = new Clave();
		cv->OtrasCondiciones=&CC;
		cv->AtributosASeleccionar = _ColSeleccion;
		cv->EjecucionMultiple=true;
		cv->IndicePrimario = getIndice(getMetadataClase().getIndicePrimario());
		stringstream ss;
		ss << "Or" << nro << ".tmp";
		cv->NombreArchivo = ss.str();

		for (list<Condicion*>::iterator itDatos=_CondicionCompuesta->Subcondiciones.begin(); itDatos!=_CondicionCompuesta->Subcondiciones.end(); ++itDatos)
		{
			for (list<MetadatosAtributo>::iterator itMetAtrib=Index->Metadata->Claves.begin();
				itMetAtrib!=Index->Metadata->Claves.end(); ++itMetAtrib)
			{
				if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
				{
					cv->ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
				}
			}
		}

		Index->BuscarClave(cv);


	};

	OperacionSeleccion::~OperacionSeleccion()
	{
	};


	OperacionInsercion::OperacionInsercion(MetadataClase* MC,list<ClaveValor>* Datos): Operacion(MC), _Datos(Datos)
	{
	};

	bool OperacionInsercion::esInsercion()
	{
		return true;
	};

	void OperacionInsercion::Ejecutar()
	{
		list<IIndice*>* ListaIndices=getIndices();
		Clave cv;
		Atributo atr;
		//cargo los datos
		for (list<ClaveValor>::iterator it=_Datos->begin(); it!=_Datos->end(); ++it)
		{
			atr.Nombre=(*it).Clave;
			atr.Valor=(*it).Valor;
			atr.Tipo=getMetadataClase().getTipoAtributo((*it).Clave);
			cv.DatosAInsertar.push_back(atr);
		}

		//inserto los datos en todos los indices
		for (list<IIndice*>::iterator it=ListaIndices->begin(); it!=ListaIndices->end(); ++it)
		{
			cv.ValoresBusqueda.clear();

			for (list<MetadatosAtributo>::iterator itMetAtrib=(*it)->Metadata->Claves.begin();
				itMetAtrib!=(*it)->Metadata->Claves.end(); ++itMetAtrib)
			{
				for (list<ClaveValor>::iterator itDatos=_Datos->begin(); itDatos!=_Datos->end(); ++itDatos)
				{

					if (((*itDatos).Clave)==((*itMetAtrib).Nombre))
					{
						cv.ValoresBusqueda.push_back((*itDatos).Valor);
					}
				}
			}

			(*it)->InsertarClave(&cv);
			_CantRegistrosAfectados=1;
		}

		ListaIndices->clear();
	};

	OperacionInsercion::~OperacionInsercion()
	{
		_Datos->clear();
	};


	OperacionActualizacion::OperacionActualizacion(MetadataClase* MC,list<ClaveValor>* Datos,CondicionCompuesta* CC): Operacion(MC), _Datos(Datos), _CondicionCompuesta(CC)
	{
	};

	void OperacionActualizacion::Ejecutar()
	{
		list<IIndice*>* ListaIndices=getIndices();

		IIndice* primario;
		for (list<IIndice*>::iterator it=ListaIndices->begin();	it!=ListaIndices->end(); ++it)
		{
			if ((*it)->Metadata->Tipo == Griego)
				primario = (*it);				
		}

		if (_CondicionCompuesta->EsAnd()){
			//busco un indice primario sobre las condiciones, si tengo llamo a EjecutarPrimario(CC)
			//sino elijo uno secundario, alguno (el mas fuerte, si hay, sino algun otro) y ejecuto la actualizacion.
			//con la info q me debueve puedo hacer un for sobre el EjecutarPrimario agregando la info sobre el IPrim			
			if (TengoInfoIndicePrimario(primario,_CondicionCompuesta)){				
				EjecutarPrimario(_CondicionCompuesta);
			}else{
				list<string>* CamposIgual=obtenerCamposIgual(_CondicionCompuesta);

				if (CamposIgual->size()>0)
				{
					IIndice* Indice;

					if (CamposIgual->size()==1)
						Indice=getIndice(getInfoIndiceDesdeNombre(*(CamposIgual->begin())));
					else
						Indice=getIndice(getInfoIndicePrimerNombreClave((*CamposIgual->begin()),_CondicionCompuesta));

					EjecutarSecundario(Indice,_CondicionCompuesta);
				}
				else
				{
					list<string>* Campos=obtenerCampos(_CondicionCompuesta);
					IIndice* Indice=getIndice(getInfoIndiceDesdeNombre(*(Campos->begin())));
					EjecutarSecundario(Indice,_CondicionCompuesta);					
				}				
			}
		}else{
			//para cada campo, debo tener un indice, sino lanzo excepcion
			//ejecuto la operacion sobre cada indice del q tengo el campo y luego para el resultado
			//llamo a EjecutarPrimario()
			list<string>* Campos=obtenerCampos(_CondicionCompuesta);
			for (list<string>::iterator itCampos=Campos->begin();itCampos!=Campos->end(); ++itCampos){
				IIndice* Indice=getIndice(getInfoIndiceDesdeNombre(*(Campos->begin())));
				if (Indice->Metadata->Tipo==Griego){
					EjecutarPrimario(_CondicionCompuesta);
				}else{
					EjecutarSecundario(Indice,_CondicionCompuesta);				
				}
			}

		}

		ListaIndices->clear();
		delete ListaIndices;
	};

	void OperacionActualizacion::EjecutarSecundario(IIndice* Indice,CondicionCompuesta* CC)
	{
		Clave cv;
		Atributo atr;
		//cargo los datos
		for (list<ClaveValor>::iterator it=_Datos->begin(); it!=_Datos->end(); ++it)
		{
			for (IteradorDeMetadatosAtributos it2=Indice->Metadata->Claves.begin();it2!=Indice->Metadata->Claves.end(); ++it2)
			{
				if (it->Clave == it2->Nombre)
				{
					atr.Nombre=(*it).Clave;
					atr.Valor=(*it).Valor;
					atr.Tipo = it2->Tipo;
					cv.DatosAInsertar.push_back(atr);
				}
			}
		}

		cv.OtrasCondiciones=CC;
		cv.EjecucionMultiple=true;

		for (list<Condicion*>::iterator itDatos=CC->Subcondiciones.begin(); itDatos!=CC->Subcondiciones.end(); ++itDatos)
		{
			for (list<MetadatosAtributo>::iterator itMetAtrib=Indice->Metadata->Claves.begin();
				itMetAtrib!=Indice->Metadata->Claves.end(); ++itMetAtrib)
			{
				if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
				{
					cv.ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
				}
			}

		}
		cv.NombreArchivo = "ActualizacionPorSec.tmp";
		Indice->ActualizarClave(&cv);

		CondicionCompuestaAND* CondicionesPrimarias=new CondicionCompuestaAND;			
		Condicion* Cnd;
		//cargo la metadata de las condiciones del indice Primario
		list<string>& Campos=getMetadataClase().getIndicePrimario()->getCampos();
		for (list<string>::iterator it=Campos.begin();it!=Campos.end();++it){
			Cnd=new CondicionIgual();
			Cnd->Simbolo=Igual;
			Cnd->ValorCondicion.Nombre=*it;
			Cnd->ValorCondicion.Tipo=getMetadataClase().getTipoAtributo(*it);
			CondicionesPrimarias->Subcondiciones.push_back(Cnd);				
		}		


		ifstream* archivo = new ifstream(cv.NombreArchivo.c_str(),ios::in);
		list<Registro>* buffer = new list<Registro>();
		bool seguir = true;

		string line;
		cv.LeerEncabezado(archivo);	

		do
		{
			seguir = cv.LeerRegistros(buffer,archivo);

			for (IteradorDeRegistros registro = buffer->begin(); registro != buffer->end(); registro++)
			{
				//completo las condiciones, con su valor
				for (list<Condicion*>::iterator itCondicionesPrim=CondicionesPrimarias->Subcondiciones.begin();itCondicionesPrim!=CondicionesPrimarias->Subcondiciones.end();++itCondicionesPrim)
				{
					for (list<Atributo>::iterator itAtrib=registro->Atributos.begin();itAtrib!=registro->Atributos.end();++itAtrib)
					{
						if ((*itCondicionesPrim)->ValorCondicion.Nombre==itAtrib->Nombre)
						{
							Condicion** c = &(*itCondicionesPrim);
							(*c)->ValorCondicion.Valor=itAtrib->Valor;							
						}					
					}				
				}
				//ejecuto sobre el primario con las condiciones obtenidas del secundario
				EjecutarPrimario(CondicionesPrimarias);				
			}
		}
		while (seguir);

		for (list<Condicion*>::iterator itCondicionesPrim=CondicionesPrimarias->Subcondiciones.begin();itCondicionesPrim!=CondicionesPrimarias->Subcondiciones.end();++itCondicionesPrim){
			Cnd=*itCondicionesPrim;								
			//libero memoria de condiciones
			delete Cnd;
		}
		CondicionesPrimarias->Subcondiciones.clear();			
	};

	void OperacionActualizacion::EjecutarPrimario(CondicionCompuesta* CondicionComp)
	{

		list<IIndice*>* ListaIndices=getIndices();

		IIndice* primario;
		for (list<IIndice*>::iterator it=ListaIndices->begin();	it!=ListaIndices->end(); ++it)
		{
			if ((*it)->Metadata->Tipo == Griego)
				primario = (*it);				
		}

		Clave cv;
		Atributo atr;
		//cargo los datos
		for (list<ClaveValor>::iterator it=_Datos->begin();
			it!=_Datos->end(); ++it){
				atr.Nombre=(*it).Clave;
				atr.Valor=(*it).Valor;					
				cv.DatosAInsertar.push_back(atr);
		}

		cv.OtrasCondiciones=CondicionComp;
		cv.EjecucionMultiple=true;

		for (list<Condicion*>::iterator itDatos=CondicionComp->Subcondiciones.begin(); itDatos!=CondicionComp->Subcondiciones.end(); ++itDatos)
		{
			for (list<MetadatosAtributo>::iterator itMetAtrib=primario->Metadata->Claves.begin();
				itMetAtrib!=primario->Metadata->Claves.end(); ++itMetAtrib)
			{
				if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
				{
					cv.ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
				}
			}
			_CantRegistrosAfectados+=cv.RegistrosAfectados;

		}
		cv.NombreArchivo = "actualizacion.tmp";
		primario->ActualizarClave(&cv);

		ifstream* archivo = new ifstream(cv.NombreArchivo.c_str(),ios::in);
		list<Registro>* buffer = new list<Registro>();
		bool seguir = true;

		string line;
		cv.LeerEncabezado(archivo);	
		this->_CantRegistrosAfectados += cv.RegistrosAfectados;

		do
		{
			seguir = cv.LeerRegistros(buffer,archivo);

			for (IteradorDeRegistros registro = buffer->begin(); registro != buffer->end(); registro++)
			{			

				//actualizo los datos en todos los indices
				for (list<IIndice*>::iterator it=ListaIndices->begin();	it!=ListaIndices->end(); ++it)
				{
					if ((*it)->Metadata->Tipo != Griego)
					{
						Clave cvSec;

						cvSec.ValoresBusqueda.clear();
						cvSec.NombreArchivo = "actualizarSec.tmp";

						cvSec.OtrasCondiciones = new CondicionCompuestaAND();
						cvSec.Resultado = new list<Registro>();

						for (IteradorDeAtributos dato = registro->Atributos.begin(); dato != registro->Atributos.end(); dato++)
						{
							bool actualizado = false;

							for (IteradorDeAtributos datoAct = cv.DatosAInsertar.begin(); datoAct != cv.DatosAInsertar.end(); datoAct++)
							{
								if (dato->Nombre == datoAct->Nombre)								
								{
									Atributo a(datoAct->Nombre,datoAct->Valor);
									a.Tipo = dato->Tipo;
									cvSec.DatosAInsertar.push_back(a);
									actualizado = true;
								}									
							}

							if (!actualizado)
								cvSec.DatosAInsertar.push_back(*dato);
						}


						for (list<MetadatosAtributo>::iterator itMetAtrib=(*it)->Metadata->Claves.begin();
							itMetAtrib!=(*it)->Metadata->Claves.end(); ++itMetAtrib)
						{
							for (IteradorDeAtributos itDatos=(*registro).Atributos.begin(); itDatos!=(*registro).Atributos.end(); ++itDatos)
							{
								if (((*itDatos).Nombre)==((*itMetAtrib).Nombre))
								{
									cvSec.ValoresBusqueda.push_back((*itDatos).Valor);
									/*CondicionIgual* igual = new CondicionIgual();
									igual->ValorCondicion = (*itDatos);
									cvSec.OtrasCondiciones->Subcondiciones.push_back(igual);*/
								}
							}
						}

						for (list<MetadatosAtributo>::iterator itMetAtrib=(*it)->Metadata->ClavePrimaria.begin();
							itMetAtrib!=(*it)->Metadata->ClavePrimaria.end(); ++itMetAtrib)
						{
							for (IteradorDeAtributos itDatos=(*registro).Atributos.begin(); itDatos!=(*registro).Atributos.end(); ++itDatos)
							{
								if (((*itDatos).Nombre)==((*itMetAtrib).Nombre))
								{
									CondicionIgual* igual = new CondicionIgual();
									igual->ValorCondicion = (*itDatos);
									cvSec.OtrasCondiciones->Subcondiciones.push_back(igual);
								}
							}
						}					


						(*it)->ActualizarClave(&cvSec);
					}

				}
			}
		}while (seguir);

		ListaIndices->clear();
		delete ListaIndices;
	};

	OperacionActualizacion::~OperacionActualizacion()
	{
		_Datos->clear();
	};


	OperacionBorrado::OperacionBorrado(MetadataClase* MC,CondicionCompuesta* CC): Operacion(MC), _CondicionCompuesta(CC)
	{
	};

	void OperacionBorrado::Ejecutar()
	{
		list<IIndice*>* ListaIndices=getIndices();

		IIndice* primario;
		for (list<IIndice*>::iterator it=ListaIndices->begin();	it!=ListaIndices->end(); ++it)
		{
			if ((*it)->Metadata->Tipo == Griego)
				primario = (*it);				
		}

		if (_CondicionCompuesta->EsAnd()){
			//busco un indice primario sobre las condiciones, si tengo llamo a EjecutarPrimario(CC)
			//sino elijo uno secundario, alguno (el mas fuerte, si hay, sino algun otro) y ejecuto la actualizacion.
			//con la info q me debueve puedo hacer un for sobre el EjecutarPrimario agregando la info sobre el IPrim			
			if (TengoInfoIndicePrimario(primario,_CondicionCompuesta)){				
				EjecutarPrimario(_CondicionCompuesta,true);
			}else{
				list<string>* CamposIgual=obtenerCamposIgual(_CondicionCompuesta);
				if (CamposIgual->size()>0){
					IIndice* Indice=getIndice(getInfoIndiceDesdeNombre(*(CamposIgual->begin())));
					EjecutarSecundario(Indice,_CondicionCompuesta,true);
				}else{
					list<string>* Campos=obtenerCampos(_CondicionCompuesta);
					IIndice* Indice=getIndice(getInfoIndiceDesdeNombre(*(Campos->begin())));
					EjecutarSecundario(Indice,_CondicionCompuesta,true);					
				}				
			}
		}else{
			//para cada campo, debo tener un indice, sino lanzo excepcion
			//ejecuto la operacion sobre cada indice del q tengo el campo y luego para el resultado
			//llamo a EjecutarPrimario()
			list<string>* Campos=obtenerCampos(_CondicionCompuesta);
			for (list<string>::iterator itCampos=Campos->begin();itCampos!=Campos->end(); ++itCampos){
				IIndice* Indice=getIndice(getInfoIndiceDesdeNombre(*(Campos->begin())));
				if (Indice->Metadata->Tipo==Griego){
					EjecutarPrimario(_CondicionCompuesta,true);
				}else{
					EjecutarSecundario(Indice,_CondicionCompuesta,true);				
				}
			}

		}

		ListaIndices->clear();
		delete ListaIndices;
	};

	void OperacionBorrado::EjecutarSecundario(IIndice* Indice,CondicionCompuesta* CC, bool llamadaRoot)
	{
		Clave cv;
		/*			Atributo atr;
		//cargo los datos
		for (list<ClaveValor>::iterator it=_Datos->begin();
		it!=_Datos->end(); ++it){
		atr.Nombre=(*it).Clave;
		atr.Valor=(*it).Valor;
		cv.DatosAInsertar.push_back(atr);
		}*/

		cv.OtrasCondiciones=CC;
		cv.EjecucionMultiple=true;

		for (list<Condicion*>::iterator itDatos=CC->Subcondiciones.begin(); itDatos!=CC->Subcondiciones.end(); ++itDatos)
		{
			for (list<MetadatosAtributo>::iterator itMetAtrib=Indice->Metadata->Claves.begin();
				itMetAtrib!=Indice->Metadata->Claves.end(); ++itMetAtrib)
			{
				if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
				{
					cv.ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
				}
			}

		}
		cv.NombreArchivo = "BorradoPorSecundario.tmp";
		Indice->EliminarClave(&cv);		
		
		if (llamadaRoot)
			_CantRegistrosAfectados+=cv.RegistrosAfectados;

		CondicionCompuestaAND* CondicionesPrimarias=new CondicionCompuestaAND;			
		Condicion* Cnd;
		//cargo la metadata de las condiciones del indice Primario
		list<string>& Campos=getMetadataClase().getIndicePrimario()->getCampos();
		for (list<string>::iterator it=Campos.begin();it!=Campos.end();++it){
			Cnd=new CondicionIgual();				
			Cnd->ValorCondicion.Nombre=*it;
			Cnd->ValorCondicion.Tipo=getMetadataClase().getTipoAtributo(*it);
			CondicionesPrimarias->Subcondiciones.push_back(Cnd);
			//CC->Subcondiciones.push_back(Cnd);
		}		

		ifstream* archivo = new ifstream(cv.NombreArchivo.c_str(),ios::in);
		list<Registro>* buffer = new list<Registro>();
		bool seguir = true;

		string line;
		cv.LeerEncabezado(archivo);	

		do
		{
			seguir = cv.LeerRegistros(buffer,archivo);

			for (IteradorDeRegistros registro = buffer->begin(); registro != buffer->end(); registro++)
			{
				//completo las condiciones, con su valor
				for (list<Condicion*>::iterator itCondicionesPrim=CondicionesPrimarias->Subcondiciones.begin();itCondicionesPrim!=CondicionesPrimarias->Subcondiciones.end();++itCondicionesPrim){
					for (list<Atributo>::iterator itAtrib=registro->Atributos.begin();itAtrib!=registro->Atributos.end();++itAtrib){
						
						if ((*itCondicionesPrim)->ValorCondicion.Nombre==itAtrib->Nombre)
						{
							Condicion** c = &(*itCondicionesPrim);
							(*c)->ValorCondicion.Valor=itAtrib->Valor;							
						}										
					}				
				}
				//ejecuto sobre el primario con las condiciones obtenidas del secundario
				EjecutarPrimario(CondicionesPrimarias,false);				
			}
		}
		while (seguir);

		for (list<Condicion*>::iterator itCondicionesPrim=CondicionesPrimarias->Subcondiciones.begin();itCondicionesPrim!=CondicionesPrimarias->Subcondiciones.end();++itCondicionesPrim){
			Cnd=*itCondicionesPrim;								
			//libero memoria de condiciones
			delete Cnd;
		}
		CondicionesPrimarias->Subcondiciones.clear();			
	};

	void OperacionBorrado::EjecutarPrimario(CondicionCompuesta* CondicionComp, bool llamadaRoot)
	{
		list<IIndice*>* ListaIndices=getIndices();
		Clave cv;

		IIndice* primario;
		for (list<IIndice*>::iterator it=ListaIndices->begin();	it!=ListaIndices->end(); ++it)
		{
			if ((*it)->Metadata->Tipo == Griego)
				primario = (*it);				
		}

		cv.OtrasCondiciones=CondicionComp;
		cv.EjecucionMultiple=true;
		cv.NombreArchivo = "borradoPrincipal.tmp";

		for (list<Condicion*>::iterator itDatos=CondicionComp->Subcondiciones.begin(); itDatos!=CondicionComp->Subcondiciones.end(); ++itDatos)
		{
			for (list<MetadatosAtributo>::iterator itMetAtrib=primario->Metadata->Claves.begin();
				itMetAtrib!=primario->Metadata->Claves.end(); ++itMetAtrib)
			{
				if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
				{
					cv.ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
				}
			}
			_CantRegistrosAfectados+=cv.RegistrosAfectados;

		}
		primario->EliminarClave(&cv);

		ifstream* archivo = new ifstream(cv.NombreArchivo.c_str(),ios::in);
		list<Registro>* buffer = new list<Registro>();
		bool seguir = true;

		string line;

		cv.LeerEncabezado(archivo);	
		if (llamadaRoot)
			_CantRegistrosAfectados += cv.RegistrosAfectados;
		do
		{
			seguir = cv.LeerRegistros(buffer,archivo);

			for (IteradorDeRegistros registro = buffer->begin(); registro != buffer->end(); registro++)
			{
				//actualizo los datos en todos los indices
				for (list<IIndice*>::iterator it=ListaIndices->begin();	it!=ListaIndices->end(); ++it)
				{
					Clave cvSec;
					if ((*it)->Metadata->Tipo != Griego)
					{
						cvSec.OtrasCondiciones = new CondicionCompuestaAND();

						for (list<MetadatosAtributo>::iterator itMetAtrib=(*it)->Metadata->Claves.begin();
							itMetAtrib!=(*it)->Metadata->Claves.end(); ++itMetAtrib)
						{
							for (IteradorDeAtributos itDatos=(*registro).Atributos.begin(); itDatos!=(*registro).Atributos.end(); ++itDatos)
							{
								if (((*itDatos).Nombre)==((*itMetAtrib).Nombre))
								{
									cvSec.ValoresBusqueda.push_back((*itDatos).Valor);
									CondicionIgual* igual = new CondicionIgual();
									igual->ValorCondicion = (*itDatos);
									cvSec.OtrasCondiciones->Subcondiciones.push_back(igual);
								}
							}
						}

						for (list<MetadatosAtributo>::iterator itMetAtrib=(*it)->Metadata->ClavePrimaria.begin();
							itMetAtrib!=(*it)->Metadata->ClavePrimaria.end(); ++itMetAtrib)
						{
							for (IteradorDeAtributos itDatos=(*registro).Atributos.begin(); itDatos!=(*registro).Atributos.end(); ++itDatos)
							{
								if (((*itDatos).Nombre)==((*itMetAtrib).Nombre))
								{
									CondicionIgual* igual = new CondicionIgual();
									igual->ValorCondicion = (*itDatos);
									cvSec.OtrasCondiciones->Subcondiciones.push_back(igual);
								}
							}
						}
						cvSec.NombreArchivo = "BorradoSec.tmp";
						(*it)->EliminarClave(&cvSec);
					}

				}

			}
		}while (seguir);

		ListaIndices->clear();

		/*cv.OtrasCondiciones=CondicionComp;
		cv.EjecucionMultiple=true;


		//elimino la clave en todos los indices
		for (list<IIndice*>::iterator it=ListaIndices->begin(); it!=ListaIndices->end(); ++it)
		{					
		for (list<Condicion*>::iterator itDatos=CondicionComp->Subcondiciones.begin(); itDatos!=CondicionComp->Subcondiciones.end(); ++itDatos)
		{
		for (list<MetadatosAtributo>::iterator itMetAtrib=(*it)->Metadata->Claves.begin();
		itMetAtrib!=(*it)->Metadata->Claves.end(); ++itMetAtrib)
		{
		if (((*itDatos)->ValorCondicion.Nombre)==((*itMetAtrib).Nombre))
		{
		cv.ValoresBusqueda.push_back((*itDatos)->ValorCondicion.Valor);
		}
		}

		}

		cv.OtrasCondiciones = CondicionComp;

		(*it)->EliminarClave(&cv);
		}		

		ListaIndices->clear();*/
	};

	OperacionBorrado::~OperacionBorrado()
	{
	};

	OperacionGetMetadataClase::OperacionGetMetadataClase(std::string Clase): NombreClase(Clase)
	{
	};

	bool OperacionGetMetadataClase::esDeMetadata()
	{
		return true;
	};

	void OperacionGetMetadataClase::Ejecutar()
	{
		HidratadorMetadataClase::hidratarDiscoARegistros(NombreClase,Resultado);
	};

	OperacionGetMetadataClase::~OperacionGetMetadataClase()
	{
	};

	OperacionExisteClase::OperacionExisteClase(std::string Clase): NombreClase(Clase)
	{
	};

	bool OperacionExisteClase::esDeMetadata()
	{
		return true;
	};

	void OperacionExisteClase::Ejecutar()
	{
		if (ConexionCapaFisica::ExisteClase(NombreClase)){
			Registro* r = new Registro();
			Atributo* atr = new Atributo();			
			atr->Valor="1";
			r->Atributos.push_back(*atr);
			Resultado->push_back(*r);

			MetadataClase* MetClase=HidratadorMetadataClase::hidratarDisco(NombreClase);
			Comun::Clase cs;
			
			cs.NombreClase=new string((MetClase->getClase()));				
			for (list<AtributoClase>::iterator it=MetClase->getAtributos().begin();it!=MetClase->getAtributos().end();++it){
				Atributo* atrib = new Atributo();
				atrib->Nombre=(*it).getNombre();
				atrib->Tipo=(*it).getTipo();
				cs.Miembros->push_back(*atrib);
			}
			stringstream streamClase;
			Comun::ConversorDeStreams::ClaseAStream(&cs,&streamClase);
			while (!streamClase.eof()){
				atr = new Atributo();
				getline(streamClase,atr->Valor);
				r =new Registro();
				r->Atributos.clear();
				r->Atributos.push_back(*atr);
				//agrego la linea a los resultados
				Resultado->push_back(*r);
			}

		}else{
			Registro* r = new Registro();
			Atributo atr;
			atr.Nombre="Existencia";
			atr.Valor="false";
			r->Atributos.push_back(atr);
			Resultado->push_back(*r);
		}
	};

	OperacionExisteClase::~OperacionExisteClase()
	{
	};

	OperacionAltaClase::OperacionAltaClase(MetadataClase* MC): Operacion(MC)
	{
	};

	void OperacionAltaClase::Ejecutar()
	{
		CrearIndice(getMetadataClase().getIndicePrimario());
		for (list<InfoIndice*>::iterator it=getMetadataClase().getIndicesSecundarios().begin();
			it!=getMetadataClase().getIndicesSecundarios().end();
			++it){
				CrearIndice(*it);
		}
	}

	bool OperacionAltaClase::esAltaClase(){
		return false;
	}

	void OperacionAltaClase::CrearIndice(InfoIndice* InfoIndex){
		IIndice* Indice=getIndice(InfoIndex);			


		Indice->Metadata->ClavePrimaria.clear();


		for (list<string>::iterator i = getMetadataClase().getIndicePrimario()->getCampos().begin();
			i != getMetadataClase().getIndicePrimario()->getCampos().end(); i++)
		{
			for (list<AtributoClase>::iterator j = getMetadataClase().getAtributos().begin();
				j != getMetadataClase().getAtributos().end(); j++)
			{
				if ((* j).getNombre() == (*i))
				{
					MetadatosAtributo* a = new MetadatosAtributo((* j).getNombre(),(* j).getTipo());
					Indice->Metadata->ClavePrimaria.push_back(*a);
				}
			}
		}

		Indice->Crear();
	};

	OperacionAltaClase::~OperacionAltaClase()
	{
	};

}
